﻿using Core;
using RI_Talisman;
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
using Verse.AI;
using WhoXiuXian;

namespace RI_Talisman
{
    public class CompBlindBoxUsing : ThingComp
    {
        private List<ResearchProjectDef> researchUnlocked;
        BlindBoxOpeningManager studyManager = new BlindBoxOpeningManager();

        public CompProperties_BlindBoxUsing Props => (CompProperties_BlindBoxUsing)props;

        public float ProgressPercent => studyManager.GetStudyProgress(parent.def);

        public bool Completed => ProgressPercent >= 1f;

        public int ProgressInt => Mathf.RoundToInt(ProgressPercent * (float)Props.cost);

        public List<ResearchProjectDef> ResearchUnlocked
        {
            get
            {
                if (researchUnlocked == null)
                {
                    researchUnlocked = new List<ResearchProjectDef>();
                    researchUnlocked.AddRange(studyManager.GetAllUnlockedResearch(parent.def));
                }

                return researchUnlocked;
            }
        }

        public override void PostSpawnSetup(bool respawningAfterLoad)
        {

            base.PostSpawnSetup(respawningAfterLoad);
        }

        public void Study(float amount, Pawn studier = null)
        {
            bool completed = Completed;
            amount *= 0.1f;
            amount *= Find.Storyteller.difficulty.researchSpeedFactor;
            studyManager.SetStudied(parent.def, amount);

            studier?.skills.Learn(SkillDefOf.Intellectual, 0.1f);
            if (completed || !Completed)
            {
                return;
            }

            QuestUtility.SendQuestTargetSignals(parent.questTags, "Researched", parent.Named("SUBJECT"));
            if (studier != null && !Props.completedLetterText.NullOrEmpty() && !Props.completedLetterTitle.NullOrEmpty())
            {
                string arg = ResearchUnlocked.Select((ResearchProjectDef r) => r.label).ToCommaList(useAnd: true);
                Find.LetterStack.ReceiveLetter(Props.completedLetterTitle.Formatted(studier.Named("STUDIER"), parent.Named("PARENT")).CapitalizeFirst(), Props.completedLetterText.Formatted(studier.Named("STUDIER"), parent.Named("PARENT")), Props.completedLetterDef ?? LetterDefOf.NeutralEvent, new List<Thing> { parent, studier });


                ThingDef thingToSpawn = Props.thingDefList.RandomElement();
                int thingDefIndex = Props.thingDefList.IndexOf(thingToSpawn);
                for (int spawning = 0; spawning < Props.thingDefListNum[thingDefIndex]; spawning++)
                {
                    if (thingToSpawn.IsWeapon || thingToSpawn.IsApparel)
                    {
                        Thing thing = GenSpawn.Spawn(thingToSpawn, studier.Position, studier.Map);
                        thing.TryGetComp<CompQuality>().SetQuality((QualityCategory)Random.Range(1, 7), (ArtGenerationContext?)1);
                    }
                    else
                    {
                        GenSpawn.Spawn(thingToSpawn, studier.Position, studier.Map);
                    }
                }
                parent.Destroy();
            }
        }


        public override IEnumerable<Gizmo> CompGetGizmosExtra()
        {
            if (!DebugSettings.ShowDevGizmos || Completed)
            {
                yield break;
            }

            Command_Action command_Action = new Command_Action();
            command_Action.defaultLabel = "DEV: Complete study";
            command_Action.action = delegate
            {
                int num = 100;
                while (!Completed && num > 0)
                {
                    Study(float.MaxValue);
                    num--;
                }
            };
            yield return command_Action;
        }

        private IEnumerable<Dialog_InfoCard.Hyperlink> GetRelatedQuestHyperlinks()
        {
            List<Quest> quests = Find.QuestManager.QuestsListForReading;
            for (int i = 0; i < quests.Count; i++)
            {
                if (quests[i].hidden || (quests[i].State != QuestState.Ongoing && quests[i].State != 0))
                {
                    continue;
                }

                List<QuestPart> partsListForReading = quests[i].PartsListForReading;
                for (int j = 0; j < partsListForReading.Count; j++)
                {
                    QuestPart_RequirementsToAcceptThingStudied questPart_RequirementsToAcceptThingStudied;
                    if ((questPart_RequirementsToAcceptThingStudied = partsListForReading[j] as QuestPart_RequirementsToAcceptThingStudied) != null && questPart_RequirementsToAcceptThingStudied.thing == parent)
                    {
                        yield return new Dialog_InfoCard.Hyperlink(quests[i]);
                        break;
                    }
                }
            }
        }

        public override IEnumerable<StatDrawEntry> SpecialDisplayStats()
        {
            IEnumerable<StatDrawEntry> enumerable = base.SpecialDisplayStats();
            if (enumerable != null)
            {
                foreach (StatDrawEntry item in enumerable)
                {
                    yield return item;
                }
            }

            yield return new StatDrawEntry(StatCategoryDefOf.BasicsNonPawn, "Reading".Translate(), ProgressInt + " / " + Props.cost, "Stat_Studiable_Desc".Translate(), 3000, null, GetRelatedQuestHyperlinks());
        }

        public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn pawn)
        {
            if (parent.def.category != ThingCategory.Item)
            {
                yield break;
            }
            if (Completed)
            {
                yield return new FloatMenuOption("CannotOpen".Translate() + " (" + "AlreadyStudied".Translate() + ")", null);
                yield break;
            }

            if (!pawn.CanReach(parent, PathEndMode.Touch, Danger.Deadly))
            {
                yield return new FloatMenuOption("CannotOpen".Translate() + " (" + "NoPath".Translate() + ")", null);
                yield break;
            }

            if (!pawn.CanReserve(parent))
            {
                yield return new FloatMenuOption("CannotOpen".Translate() + " (" + "Reserved".Translate() + ")", null);
                yield break;
            }

            if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
            {
                yield return new FloatMenuOption("CannotOpen".Translate() + " (" + "Incapable".Translate().CapitalizeFirst() + ")", null);
                yield break;
            }

            Thing researchBench = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(RI_BuildingsDefOf.RI_Building_HiTechResearchDesk), PathEndMode.InteractionCell, TraverseParms.For(pawn, Danger.Some), 9999f, (Thing t) => pawn.CanReserve(t));

            if (researchBench == null)
            {
                researchBench = GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(RI_BuildingsDefOf.RI_Building_StudyDesk), PathEndMode.InteractionCell, TraverseParms.For(pawn, Danger.Some), 9999f, (Thing t) => pawn.CanReserve(t));
            }
            if (researchBench == null)
            {
                yield return new FloatMenuOption("CannotOpen".Translate() + " (" + "NoResearchBench".Translate() + ")", null);
                yield break;
            }

            TaggedString taggedString = "Expose".Translate();
            _ = ResearchUnlocked;

            yield return new FloatMenuOption(taggedString, delegate
            {
                if (pawn.CanReserveAndReach(parent, PathEndMode.Touch, Danger.Deadly))
                {
                    Job job = JobMaker.MakeJob(RI_T_DefOfs.RI_Job_OpenBlindBox/*JobDefOf.StudyItem*/, parent, researchBench, researchBench.Position);
                    pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
                }
            });
        }

        public bool CanBeUsedBy(Pawn p, out string failReason)
        {
            failReason = null;
            return true;
        }

        public override void PostExposeData()
        {
            base.PostExposeData();
            if (Scribe.mode != LoadSaveMode.LoadingVars)
            {
                return;
            }

            float value = 0f;
            Scribe_Values.Look(ref value, "progress", 0f);
            if (value > 0f)
            {
                float num = value / (float)Props.cost;
                float studyProgress = studyManager.GetStudyProgress(parent.def);
                if (num > studyProgress)
                {
                    studyManager.ForceSetStudiedProgress(parent.def, num);
                }
            }
        }

        public override string CompInspectStringExtra()
        {
            return null;
        }
    }

}